package com.peaksport.framework.metadata.filter;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.peaksport.framework.exception.PKDevException;
import com.peaksport.framework.map.ListMap;
import com.peaksport.framework.metadata.venum.CompareTypeEnum;
import com.peaksport.framework.metadata.venum.ValueTypeEnum;
import com.peaksport.framework.util.PKPublicUtils;

/**
 * 
 * compareExpr 如果是字段名的话，用字段别名(去字段前缀f/F),在SQL解析时会再自动转换成实际的字段名(包含表别名.字段名）
 *
 * 例子：  TODO 整理更合适的具体例子
 *           new FilterItemInfo("user.number","xxxx");
 *           new FilterItemInfo("user.number","yyyy",CompareTypeEnum.LESS) ;
 *           new FilterItemInfo("user.loginCount",5);
 *           new FilterItemInfo("user.number","select fnumber from t_pm_user where Fid='#bill.creator.number#", CompareTypeEnum.INCLUDE);
 *           new FilterItemInfo("user.number",new ArrayList<>(), CompareTypeEnum.INCLUDE);
 *           new FilterItemInfo(null,"select 1 from t_pm_user where fid='#bill.creator.number#",CompareTypeEnum.EXISTS);
 *           new FilterItemInfo("user.createTime",new Date(),CompareTypeEnum.GREATER_EQUALS);
 *           new FilterItemInfo("user.id",null,CompareTypeEnum.ISNOT);
 *           TODO SQL脚本类型的
 *           new ECAFilterItemInfo("user.number","#bill.creator.number#%", CompareTypeEnum.LIKE); 
 *
 * @author jinbin_guo 2019年4月15日
 *
 */
public class FilterItemInfo {
    /** 逗号 , */
    private static final String COMMA = PKPublicUtils.COMMA;
    /** 引号 ' */
    private static final String QUOTE = PKPublicUtils.QUOTE;
    /** 空格字符   */
    private static final String SPACE = PKPublicUtils.SPACE;
    /** #号*/
    private static final String POUND_SIGN= PKPublicUtils.POUND_SIGN;

    /** 通配符 % */
  //  private static final String WILD_CARD_ANY = "%";
    /** 实体过滤属性*/
    private String compareExpr;
    /** 属性对应的数据库字段,含表别名 */
    private String dbField;
    /** 过滤条件比较值*/
    private Object compareValue;
    /** 比较值类型 */
    private ValueTypeEnum valueType;
    /** 比较方式 */
    private CompareTypeEnum compareType;
    /** SQL 片段过滤脚本*/
    private String sqlFitler;
    /**
     * 扩展属性字段的映射关系，可能应用在exists、sqlFilter的sql片段中，把属性替代成真正的表&字段
     *  sql片段用#properyMame.properytName2.propertyName3#表示
     * */
    private ListMap<String> propertyMappingEx = new ListMap<>();

    public FilterItemInfo() {
        this(null,null,null);
    }
    public FilterItemInfo(String compareExpr, Object compareValue) {
        this(compareExpr, compareValue,CompareTypeEnum.EQUALS);
    }
    public FilterItemInfo(String compareExpr, Object compareValue, CompareTypeEnum compareType) {
        this(compareExpr, compareValue, compareType,null);
    }
    public FilterItemInfo(String compareExpr, Object compareValue, CompareTypeEnum compareType, ValueTypeEnum valueType) {
        this.compareExpr = compareExpr;
        this.compareValue = compareValue;
        this.compareType = compareType;
        this.valueType = valueType;
        addPropertyMapping();
    }
    public FilterItemInfo(String sqlFitler) {
        this.sqlFitler = sqlFitler;
        valueType = ValueTypeEnum.SQL;
        addPropertyMapping();

    }

    public String getCompareExpr() {
        return compareExpr;
    }
    public void setCompareExpr(String compareExpr) {
        this.compareExpr = compareExpr;
    }

    public String getDbField() {
        return dbField;
    }
    public void setDbField(String dbField) {
        this.dbField = dbField;
    }

    public CompareTypeEnum getCompareType() {
        return compareType;
    }
    public void setCompareType(CompareTypeEnum compareType) {
        this.compareType = compareType;
    }

    public Object getCompareValue() {
        return compareValue;
    }
    public void setCompareValue(Object compareValue) {
        this.compareValue = compareValue;
    }

    public void setValueTypeEnum(ValueTypeEnum valueType) {
        this.valueType = valueType;
    }
    public ValueTypeEnum getValueType() {
        return valueType;
    }

    public String getSqlFitler() {
        return sqlFitler;
    }

    public void setSqlFitler(String sqlFitler) {
        this.sqlFitler = sqlFitler;
    }

    public ListMap<String> getPropertyMappingEx() {
        return propertyMappingEx;
    }

    /**
     * 检查过滤条件类型
     */
    private void verifyCompareType() {
        if (compareType == null)
            throw PKDevException.throwException("compareType不能为空");
    }

    /**
     * 检查过滤条件属性字段或表达式
     */
    private void verifyCompareExpr() {
        if (sqlFitler == null) return;
        else if (PKPublicUtils.equalsAny(compareType,CompareTypeEnum.EXISTS,CompareTypeEnum.NOTEXISTS)) return;
        else if (PKPublicUtils.isEmpty(compareExpr)) {
            throw PKDevException.throwException("compareExpr不能为空");
        }
    }

    /**
     *  检查过滤条件值
     */
    @SuppressWarnings("rawtypes")
	private void verifyCompareValue() {
        if (PKPublicUtils.equalsAny(compareType,CompareTypeEnum.IS,CompareTypeEnum.ISNOT)) return;
        else if (compareValue == null) {
            throw PKDevException.throwException("compareValue不能为空");
        } else if (compareValue instanceof List &&  ((List)compareValue).size() == 0) {
            throw PKDevException.throwException("compareValue不能为空集合");
        } else if (PKPublicUtils.equalsAny(compareType,CompareTypeEnum.EXISTS,CompareTypeEnum.NOTEXISTS) && !(compareValue instanceof String)) {
            throw PKDevException.throwException("[exists] or [not exists]的比较值暂不支持类型[%s]",compareValue.getClass());
        }
    }

    /**
     * 根据指定值类型重新将字符类型值进行转化
     */
    @SuppressWarnings("deprecation")
	private void rechangeValueByType() {
        try {
            if (valueType == null || compareValue == null) return;
            else if (PKPublicUtils.equals(valueType, ValueTypeEnum.INT) && compareValue instanceof  String) {
                compareValue = Integer.parseInt((String)compareValue);
            } else if (PKPublicUtils.equals(valueType, ValueTypeEnum.DATE) && compareValue instanceof  String) {
                compareValue = new Date((String)compareValue);
            } else if (PKPublicUtils.equals(valueType, ValueTypeEnum.DECIMAL) && compareValue instanceof  String) {
                compareValue = new BigDecimal((String)compareValue);
            }
        } catch (Exception exc) {
            throw PKDevException.throwException("过滤条件值类型转换错误,请检查query文件：" + PKPublicUtils.getStackTrace(exc));
        }
    }

    /**
     *  解析含属性字段SQL片段
     * @param sqlFragment
     * @return
     */
    private String[] getProperyForSqlFragment(String sqlFragment) {
        if (sqlFragment == null) return null;
        Pattern p= Pattern.compile("#[\\s\\S]+#");
        Matcher m=p.matcher(sqlFragment);
        Vector<String> vec = new Vector<>();
        while(m.find()) {
            String s = m.group();
            vec.add(s.replace("#",""));
        }
        if (vec.isEmpty()) return null;
        return PKPublicUtils.vectorToString(vec);
    }

    /**
     *  解析增加带有属性字段sql片段,待解析SQL语句时一并解析成对应的数据库字段
     */
    private void addPropertyMapping() {
        String sqlFragment = null;
        if (sqlFitler != null) sqlFragment = sqlFitler;
        else if (PKPublicUtils.equalsAny(compareType,CompareTypeEnum.INCLUDE,CompareTypeEnum.NOTINCLUDE) && compareValue instanceof String) {
            sqlFragment = (String)compareValue;
        } else if (PKPublicUtils.equalsAny(compareType,CompareTypeEnum.EXISTS,CompareTypeEnum.NOTEXISTS)) {
            sqlFragment = (String)compareExpr;
        } else if (compareValue instanceof String) {
            sqlFragment = (String)compareValue;
        }

        String[] property = getProperyForSqlFragment(sqlFragment);
        if (property == null) return;
        for (int i = 0, len = property.length; i < len; i++) {
            propertyMappingEx.add(property[i],null);
        }
    }

    /**
     * 替代属性字段成相应的数据库字段
     * @param sqlFragment
     * @return
     */
    private String replaceProperty2dbField(String sqlFragment) {
         for (int i = 0, len = propertyMappingEx.size(); i < len; i++) {
             String property = propertyMappingEx.get(i);
             String dbField = propertyMappingEx.get(property);
             if (dbField == null)
                 throw PKDevException.throwException("属性字段[%s]未映射相应的数据库字段,请联系系统管理员.",property);
             sqlFragment = sqlFragment.replace(new StringBuffer(POUND_SIGN).append(property).append(POUND_SIGN).toString(),dbField);
         }
        return sqlFragment;
    }

    @SuppressWarnings("rawtypes")
	public String toSQL() {
        StringBuffer sql = new StringBuffer();
        rechangeValueByType();
        verifyCompareType();
        verifyCompareExpr();
        verifyCompareValue();
        boolean hasPropertyMapping = !propertyMappingEx.isEmpty();

        if (sqlFitler != null) {
            return replaceProperty2dbField(sqlFitler);
        }  else if(PKPublicUtils.equalsAny(compareType,CompareTypeEnum.IS,CompareTypeEnum.ISNOT)) {
            sql.append(replaceProperty2dbField(compareExpr)).append(SPACE).append(compareType.getValue()).append(" null");
            return sql.toString();
        } else  if (PKPublicUtils.equalsAny(compareType, CompareTypeEnum.EXISTS,CompareTypeEnum.NOTEXISTS)) {
            sql.append(compareType.getValue()).append(" (").append(replaceProperty2dbField((String)compareValue)).append(")");
            return sql.toString();
        } else if (PKPublicUtils.equalsAny(compareType,CompareTypeEnum.INCLUDE,CompareTypeEnum.NOTINCLUDE)) {
            sql.append(dbField).append(SPACE);
            if (compareValue instanceof  List) {
                sql.append(compareType.getValue()).append(" (");
                for (int i = 0,len = ((List)compareValue).size(); i < len; i++) {
                    Object value = ((List)compareValue).get(i);
                    if (value instanceof String) {
                        sql.append(QUOTE).append((String)value).append(QUOTE);
                    } else if (value instanceof Integer) {
                        sql.append(value);
                    } else if (value instanceof BigDecimal) {
                        sql.append(PKPublicUtils.getBigDecimal(value));
                    } else {
                        throw PKDevException.throwException("[in] or [not in]的比较值暂不支持类型[%s]",value.getClass());
                    }
                    if (i != (len-1))
                        sql.append(COMMA);
                }
                sql.append(")");

            } else if (compareValue instanceof  String) {
                // 如sql片段 ... in (select fid from t_pm_user where fnumber='#user.id#')
                sql.append(compareType.getValue()).append(SPACE).append("(").append(replaceProperty2dbField((String)compareValue)).append(")");
            } else {
                throw PKDevException.throwException("[in] or [not in]的比较值类型必须为java.util.List,非法类型[%s]",compareValue.getClass());
            }
            return sql.toString();
        }  else if (PKPublicUtils.equalsAny(compareType,CompareTypeEnum.LIKE,CompareTypeEnum.NOTLIKE)){
            if (!(compareValue instanceof String)) {
                throw PKDevException.throwException("[like] or [not like]的比较值类型必须为java.lang.String,非法类型[%s]",compareValue.getClass());
            }
            if (PKPublicUtils.equals(ValueTypeEnum.SQL,valueType)) {
                sql.append(dbField).append(SPACE).append((compareType.getValue())).append(SPACE).append("(").append(compareValue).append(")");
            } else {
                sql.append(dbField).append(SPACE).append((compareType.getValue())).append(SPACE).append(QUOTE).append(compareValue).append(QUOTE);
            }
            return sql.toString();
        } else {
            sql.append(dbField).append(SPACE).append(compareType.getValue()).append(SPACE);
            if (compareValue instanceof String) {
                if (hasPropertyMapping) {
                    sql.append(replaceProperty2dbField((String)compareValue));
                } if (PKPublicUtils.equals(valueType,ValueTypeEnum.SQL)) {
                    sql.append((String)compareValue);
                } else {
                    sql.append(QUOTE).append((String)compareValue).append(QUOTE);
                }
            } else if (compareValue instanceof Integer) {
               sql.append(((Integer) compareValue).intValue()) ;
            } else if (compareValue instanceof BigDecimal) {
                sql.append(PKPublicUtils.getBigDecimal(compareValue));
            } else if (compareValue instanceof Date) {
                sql.append(PKPublicUtils.SDF_YYYYMMDD_HHMMSS.format(compareValue));
            } else {
                throw PKDevException.throwException("比较类型[%s]的比较值暂不支持类型[%s]",compareType.getClass(),compareValue.getClass());
            }
            return sql.toString();
        }
    }
}
